// system
#include <stdio.h>				// for printf
#include <string.h>			// for memcpy
// event
#include "event_config.h"
#include "eventDetection_module.h"
// gtrack
#include "gtrack_config.h"
#include "gtrack_int.h"
// cJSON
#include "cJSON.h"
#include "typedef.h"

#define VALID_DOULBE(num) (cJSON_IsNumber(num))
#define VALID_INT(num) (cJSON_IsNumber(num))

void event_config_save(const char* filename, const void* config)
{
	const event_moduleConfig* p_config = (const event_moduleConfig*)config;
	cJSON* root = cJSON_CreateObject();

	/**  @brief  ���ӻ����������� */
	cJSON_AddNumberToObject(root, "max_target_num", p_config->maxNumTarget);

	/**  @brief  ���ӵ�·�������� */
	cJSON* lane_obj = cJSON_CreateObject();
	const event_roadBaseParams* lane_conf = &(p_config->laneParams);
	cJSON* points = cJSON_CreateArray();
	for (int i = 0; i < lane_conf->numControlPoints; i++)
	{
		cJSON* point = cJSON_CreateFloatArray(lane_conf->ControlPoints[i].array, 2);
		cJSON_AddItemToArray(points, point);
	}
	cJSON* detect_zones = cJSON_CreateArray();
	for (int i = 0; i < lane_conf->maxNumLanes; i++)
	{
		cJSON* detect_zone = cJSON_CreateFloatArray(lane_conf->detectZone[i].zone, 2);
		cJSON_AddItemToArray(detect_zones, detect_zone);
	}
	cJSON* max_speeds = cJSON_CreateFloatArray(lane_conf->max_speed, lane_conf->maxNumLanes);
	cJSON* min_speeds = cJSON_CreateFloatArray(lane_conf->min_speed, lane_conf->maxNumLanes);
	cJSON* detection_line = cJSON_CreateFloatArray(lane_conf->detection_line, lane_conf->maxNumLanes);
	cJSON* lane_travel_direction = cJSON_CreateIntArray((int*)lane_conf->moveDirection, lane_conf->maxNumLanes);
	cJSON* lane_line_type = cJSON_CreateIntArray((int*)lane_conf->type, lane_conf->maxNumLanes);

	cJSON_AddNumberToObject(lane_obj, "control_point_num", lane_conf->numControlPoints);
	cJSON_AddNumberToObject(lane_obj, "lane_num", lane_conf->maxNumLanes);
	cJSON_AddNumberToObject(lane_obj, "lane_Insert_direction", lane_conf->direction);
	cJSON_AddNumberToObject(lane_obj, "lane_width", lane_conf->width);
	cJSON_AddItemToObject(lane_obj, "max_speeds", max_speeds);
	cJSON_AddItemToObject(lane_obj, "min_speeds", min_speeds);
	cJSON_AddItemToObject(lane_obj, "detection_line", detection_line);
	cJSON_AddItemToObject(lane_obj, "lane_travel_direction", lane_travel_direction);
	cJSON_AddItemToObject(lane_obj, "lane_line_type", lane_line_type);
	cJSON_AddItemToObject(lane_obj, "control_points", points);
	cJSON_AddItemToObject(lane_obj, "detect_zones", detect_zones);
	cJSON_AddItemToObject(root, "lane_param", lane_obj);

	/**  @brief  �����¼����������� */
	const event_ThresholdParam* event_thd_conf = &(p_config->thresholdParam);
	cJSON* event_thd_obj = cJSON_CreateObject();
	// �汾�Ų�д�� 
	// ...
	cJSON_AddNumberToObject(event_thd_obj, "min_speed", event_thd_conf->absolute_min_speed);
	cJSON_AddNumberToObject(event_thd_obj, "traffic_jam_speed", event_thd_conf->traffic_jam_speed);
	// �����¼���ֵ����
	cJSON* reversed_driving_thd_obj = cJSON_CreateObject();
	const EventThreshold* reversed_driving_thd_conf = &(event_thd_conf->reversed_driving);
	cJSON_AddNumberToObject(reversed_driving_thd_obj, "duration_ms", reversed_driving_thd_conf->duration_ms);
	cJSON_AddNumberToObject(reversed_driving_thd_obj, "duration_frame", reversed_driving_thd_conf->duration_stamp);
	cJSON_AddNumberToObject(reversed_driving_thd_obj, "lower_multiplier", reversed_driving_thd_conf->lower_multiplier);
	cJSON_AddNumberToObject(reversed_driving_thd_obj, "upper_multiplier", reversed_driving_thd_conf->upper_multiplier);
	cJSON_AddItemToObject(event_thd_obj, "reversed_driving_thd", reversed_driving_thd_obj);
	// �Ƿ������ֵ����
	cJSON* lane_change_thd_obj = cJSON_CreateObject();
	const EventThreshold* lane_change_thd_conf = &(event_thd_conf->lane_change);
	cJSON_AddNumberToObject(lane_change_thd_obj, "duration_ms", reversed_driving_thd_conf->duration_ms);
	cJSON_AddNumberToObject(lane_change_thd_obj, "duration_frame", reversed_driving_thd_conf->duration_stamp);
	cJSON_AddNumberToObject(lane_change_thd_obj, "lower_multiplier", reversed_driving_thd_conf->lower_multiplier);
	cJSON_AddNumberToObject(lane_change_thd_obj, "upper_multiplier", reversed_driving_thd_conf->upper_multiplier);
	cJSON_AddItemToObject(event_thd_obj, "lane_change_thd", lane_change_thd_obj);
	// ���١������¼���ֵ����
	cJSON* speed_thd_obj = cJSON_CreateObject();
	const EventThreshold* speed_thd_conf = &(event_thd_conf->speed);
	cJSON_AddNumberToObject(speed_thd_obj, "duration_ms", speed_thd_conf->duration_ms);
	cJSON_AddNumberToObject(speed_thd_obj, "duration_frame", speed_thd_conf->duration_stamp);
	cJSON_AddNumberToObject(speed_thd_obj, "lower_multiplier", speed_thd_conf->lower_multiplier);
	cJSON_AddNumberToObject(speed_thd_obj, "upper_multiplier", speed_thd_conf->upper_multiplier);
	cJSON_AddItemToObject(event_thd_obj, "speed_thd", speed_thd_obj);
	cJSON_AddItemToObject(root, "event_thd_param", event_thd_obj);

	write_json_file(filename, root);
	cJSON_Delete(root);
}

void get_default_event_config(event_moduleConfig* p_config)
{
	/**  @brief �������� */
	p_config->thresholdParam.major_version = 1;
	p_config->thresholdParam.minor_version = 0;
	p_config->maxNumTarget = 250;



	/**  @brief �¼������ֵ���� */
	EventThreshold event_thd = { 1000, 10, 1.1f, 0.9f };

	p_config->thresholdParam.absolute_min_speed = 1.f;
	p_config->thresholdParam.traffic_jam_speed = 10.f;
	p_config->thresholdParam.speed = event_thd;
	p_config->thresholdParam.lane_change = event_thd;
	p_config->thresholdParam.reversed_driving = event_thd;

	/**  @brief ��·���� */
	#define CONTROL_POINT_NUM       3
	#define MAX_LANE_NUM 			3

	Point2D cp[CONTROL_POINT_NUM] = { { 6.f , 0.f }, { 6.f , 400.f }, { 6.f , 800.f } };
	float max_speed[MAX_LANE_NUM] = { 33.33f, 33.33f, 33.33f };
	float min_speed[MAX_LANE_NUM] = { 16.67f, 16.67f, 16.67f };
	laneDirection lane_dir[MAX_LANE_NUM] = { MOVING_TOWARD , MOVING_TOWARD, MOVING_TOWARD };
	laneType type[MAX_LANE_NUM] = { SOLIDLINE, DOTTEDLINE, SOLIDLINE };
	DetectionZone dect_zone[MAX_LANE_NUM] = { { 100.f, 400.f }, { 100.f, 400.f }, { 100.f, 400.f } };
	float detection_line[MAX_LANE_NUM] = { 200, 200, 200 };

	p_config->laneParams.numControlPoints = CONTROL_POINT_NUM;
	p_config->laneParams.maxNumLanes = MAX_LANE_NUM;
	p_config->laneParams.width = 4;
	p_config->laneParams.direction = INSERT_LEFT;
	memcpy(p_config->laneParams.ControlPoints, cp, CONTROL_POINT_NUM * sizeof(Point2D));
	memcpy(p_config->laneParams.max_speed, max_speed, MAX_LANE_NUM * sizeof(float));
	memcpy(p_config->laneParams.min_speed, min_speed, MAX_LANE_NUM * sizeof(float));
	memcpy(p_config->laneParams.moveDirection, lane_dir, MAX_LANE_NUM * sizeof(laneDirection));
	memcpy(p_config->laneParams.type, type, MAX_LANE_NUM * sizeof(laneType));
	memcpy(p_config->laneParams.detectZone, dect_zone, MAX_LANE_NUM * sizeof(DetectionZone));
	memcpy(p_config->laneParams.detection_line, detection_line, MAX_LANE_NUM * sizeof(float));
}

void parse_event_threshold_data(const cJSON* data, EventThreshold* event_threshold)
{
	cJSON* duration_ms = cJSON_GetObjectItemCaseSensitive(data, "duration_ms");
	cJSON* duration_frame = cJSON_GetObjectItemCaseSensitive(data, "duration_frame");
	cJSON* lower_multiplier = cJSON_GetObjectItemCaseSensitive(data, "lower_multiplier");
	cJSON* upper_multiplier = cJSON_GetObjectItemCaseSensitive(data, "upper_multiplier");
	parse_u_short_data(duration_ms, &(event_threshold->duration_ms));
	parse_u_short_data(duration_frame, &(event_threshold->duration_stamp));
	parse_float_data(lower_multiplier, &(event_threshold->lower_multiplier));
	parse_float_data(upper_multiplier, &(event_threshold->upper_multiplier));
}

void parse_json_event_data(const cJSON* root, event_moduleConfig* p_config)
{
	if (!root)
	{
		return;
	}

	/**  @brief  �������� */
	cJSON* max_target_num = cJSON_GetObjectItemCaseSensitive(root, "max_target_num");
	cJSON* lane_param = cJSON_GetObjectItemCaseSensitive(root, "lane_param");
	cJSON* event_thd_param = cJSON_GetObjectItemCaseSensitive(root, "event_thd_param");
	parse_u_short_data(max_target_num, &(p_config->maxNumTarget));

	/**  @brief  ��·���� */
	if (cJSON_IsObject(lane_param))
	{
		event_roadBaseParams* road_conf = &(p_config->laneParams);
		cJSON* control_point_num = cJSON_GetObjectItemCaseSensitive(lane_param, "control_point_num");
		cJSON* lane_num = cJSON_GetObjectItemCaseSensitive(lane_param, "lane_num");
		cJSON* lane_Insert_direction = cJSON_GetObjectItemCaseSensitive(lane_param, "lane_Insert_direction");
		cJSON* lane_width = cJSON_GetObjectItemCaseSensitive(lane_param, "lane_width");
		cJSON* max_speeds = cJSON_GetObjectItemCaseSensitive(lane_param, "max_speeds");
		cJSON* min_speeds = cJSON_GetObjectItemCaseSensitive(lane_param, "min_speeds");
		cJSON* detection_line = cJSON_GetObjectItemCaseSensitive(lane_param, "detection_line");
		cJSON* lane_travel_direction = cJSON_GetObjectItemCaseSensitive(lane_param, "lane_travel_direction");
		cJSON* lane_line_type = cJSON_GetObjectItemCaseSensitive(lane_param, "lane_line_type");
		cJSON* detect_zones = cJSON_GetObjectItemCaseSensitive(lane_param, "detect_zones");
		cJSON* control_points = cJSON_GetObjectItemCaseSensitive(lane_param, "control_points");
		parse_u_short_data(control_point_num, &(road_conf->numControlPoints));
		road_conf->numControlPoints = MIN(road_conf->numControlPoints, EVENT_MAX_CONTROL_POINTS);
		parse_u_short_data(lane_num, (uint16_t*)&(road_conf->maxNumLanes));
		road_conf->maxNumLanes = MIN(road_conf->maxNumLanes, EVENT_MAX_LANE_NUM);
		parse_u_short_data(lane_Insert_direction, (uint16_t*)&(road_conf->direction));
		road_conf->direction = road_conf->direction != 0 ? INSERT_RIGHT : INSERT_LEFT;
		parse_float_data(lane_width, &(road_conf->width));
		parse_float_array(max_speeds, road_conf->max_speed, road_conf->maxNumLanes);
		parse_float_array(min_speeds, road_conf->min_speed, road_conf->maxNumLanes);
		parse_float_array(detection_line, road_conf->detection_line, road_conf->maxNumLanes);
		parse_int_array(lane_travel_direction, (int*)road_conf->moveDirection, road_conf->maxNumLanes);
		parse_int_array(lane_line_type, (int*)road_conf->type, road_conf->maxNumLanes);
		
		for (int i = 0; i < road_conf->maxNumLanes; i++)
		{
			road_conf->moveDirection[i] = road_conf->moveDirection[i] != 0 ? MOVING_TOWARD : MOVING_AWAY;
			road_conf->type[i] = road_conf->type[i] != 0 ? DOTTEDLINE : SOLIDLINE;
		}
		if (cJSON_IsArray(detect_zones))
		{
			int detect_zones_size = cJSON_GetArraySize(detect_zones);
			detect_zones_size = MIN(detect_zones_size, road_conf->maxNumLanes);
			cJSON* child = detect_zones->child;
			for (int i = 0; i < detect_zones_size; i++)
			{
				parse_float_array(child, road_conf->detectZone[i].zone, 2);
				child  = child->next;
			}
		}
		if (cJSON_IsArray(control_points))
		{
			int control_points_size = cJSON_GetArraySize(control_points);
			control_points_size = MIN(control_points_size, road_conf->numControlPoints);
			cJSON* child = control_points->child;
			for (int i = 0; i < control_points_size; i++)
			{
				parse_float_array(child, road_conf->ControlPoints[i].array, 2);
				child = child->next;
			}
		}
	}

	/**  @brief  �¼������� */
	if (cJSON_IsObject(event_thd_param))
	{
		event_ThresholdParam* event_thd_conf = &(p_config->thresholdParam);
		cJSON* min_speed = cJSON_GetObjectItemCaseSensitive(event_thd_param, "min_speed");
		cJSON* traffic_jam_speed = cJSON_GetObjectItemCaseSensitive(event_thd_param, "traffic_jam_speed");
		cJSON* reversed_driving_thd = cJSON_GetObjectItemCaseSensitive(event_thd_param, "reversed_driving_thd");
		cJSON* lane_change_thd = cJSON_GetObjectItemCaseSensitive(event_thd_param, "lane_change_thd");
		cJSON* speed_thd = cJSON_GetObjectItemCaseSensitive(event_thd_param, "speed_thd");
		parse_float_data(min_speed, &(event_thd_conf->absolute_min_speed));
		parse_float_data(traffic_jam_speed, &(event_thd_conf->traffic_jam_speed));
		if (cJSON_IsObject(reversed_driving_thd))
		{
			EventThreshold* reversed_driving_thd_conf = &(event_thd_conf->reversed_driving);
			parse_event_threshold_data(reversed_driving_thd, reversed_driving_thd_conf);
		}
		if (cJSON_IsObject(lane_change_thd))
		{
			EventThreshold* lane_change_thd_conf = &(event_thd_conf->lane_change);
			parse_event_threshold_data(lane_change_thd, lane_change_thd_conf);
		}
		if (cJSON_IsObject(speed_thd))
		{
			EventThreshold* speed_thd_conf = &(event_thd_conf->speed);
			parse_event_threshold_data(speed_thd, speed_thd_conf);
		}
	}
}

int event_config_load(const char* filename, void* config)
{
	event_moduleConfig* p_config = (event_moduleConfig*)config;
	get_default_event_config(p_config);
	cJSON* root = read_json_file(filename);
	if (!root)
	{
		const char* error_ptr = cJSON_GetErrorPtr();
		printf("JSON ��������: %s\n", error_ptr);
		return 0;
	}
	parse_json_event_data(root, p_config);
	return 1;
}